import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.InetAddress;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Date;
import java.util.Properties;
import java.util.Vector;
import java.io.*;
import java.util.*;
import org.jdom.*;
import org.jdom.output.*;


/**
 *
 * @author Alejandro Figueroa
 */
public class AccesoRemoto extends UnicastRemoteObject implements ITanqueRemoto{

    // <editor-fold defaultstate="collapsed" desc="Variables">

    public int puerto = 0;
    public boolean alarma;
    public int capacidadTanque = 0;
    public int capacidadMaxima;
    public String ip;
    public String url;
    public int puerto2;
    public ITanqueRemoto obj = null;
    public Loggers bitacora = new Loggers();
    public Pantalla ventana;
    public AccesoRemoto server;
    public int numeroPropio;
    public int numeroProximo;
    public int puertoPropioPrincipal;
    public int capacidadPropia;
    public int capacidadProximo;
    public javax.swing.Timer t;


    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Constructores">

    public AccesoRemoto() throws RemoteException
    {
        super();

        Properties props = new Properties();

        alarma= false;

        try
        {
            props.load(new FileInputStream("tanque.properties"));

            numeroPropio = Integer.parseInt(props.getProperty("numeroPropio"));
            numeroProximo = Integer.parseInt(props.getProperty("numeroProximo"));
            ip = props.getProperty("IPProximo");
            puerto = Integer.parseInt(props.getProperty("puertoProximo"));
            puerto2 = Integer.parseInt(props.getProperty("puertoPropio"));
            puertoPropioPrincipal = Integer.parseInt(props.getProperty("puertoPropioPrincipal"));
            capacidadMaxima = Integer.parseInt(props.getProperty("capacidadPropia"));
            capacidadProximo = Integer.parseInt(props.getProperty("capacidadProximo"));
            url = "//" + ip + ":" + puerto + "/Tanque"+numeroProximo;

            //System.out.println(IPProximo);
        }catch (Exception e)
        {

        }

        ventana = new Pantalla(this);
        ventana.setVisible(true);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Implementacion de ITanqueRemoto">

    /**
     * Metodo encargado de recibir el contenido de la entrada de petroleo
     * que sera ingresada en el tanque
     * @param tanques: contenido de petroleo que sera inscrito en el xml
     * @throws RemoteException
     */
    public void EscribirTanquesXml(Vector tanques) throws RemoteException
    {
        //Creamos un elemento root
        Element root=new Element("tanque");

        int tam = tanques.size();
        TanquesLlenar tanque = new TanquesLlenar();

        for (int i =0; i<tam; i++)
        {
            tanque = (TanquesLlenar) tanques.elementAt(i);

            Element id = new Element("id").setText(tanque.getid());
            Element lts = new Element("lts").setText(tanque.getlts());
            root.addContent(id);
            root.addContent(lts);
        }

        Document doc=new Document(root);

        /**
         * Hacemos la escritura en el xml
         */
        try
        {
            XMLOutputter out=new XMLOutputter(Format.getPrettyFormat());
            FileOutputStream file=new FileOutputStream("litros_tanques.xml");
            out.output(doc,file);
            file.flush();
            file.close();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        this.leerArchivoEntradas();

    }

    /**
     * Metodo encargado de realizar la transferencia de los litros sobrantes
     * al otro tanque
     * @param litros: cantidad de litros a transferir
     * @param tanquesFull: en caso de que venga porque los tanques pasan su capacidad maxima
     * se envia aqui el numero de tanques de capacidad max ha sido sobrepasada
     */

    public void transferirLitros (int litros, int tanquesFull){

        try{

            obj = (ITanqueRemoto) Naming.lookup(url);
            obj.recibirPetroleo(litros,tanquesFull);

            bitacora.escribirBitacora("Litros: " + String.valueOf(litros) , "transferir", "Capacidad superior 70%");

        }catch (Exception e) {

            bitacora.escribirBitacora("Litros: " + String.valueOf(litros), "transferir", "Error al transferir");

        }

    }

    /**
     * Metodo encargado de Recibir la cantidad de litros de otro tanque
     * y de luego llamar al revisar tanques a ver que pasa
     * @param litrosRecibidos: litros que se quieren sumar al tanque
     * @param tanquesFull: en caso de que venga porque los tanques pasan su capacidad maxima
     * se envia aqui el numero de tanques de capacidad max ha sido sobrepasada
     */
    public void recibirPetroleo (int litrosRecibidos, int tanquesFull){

        this.revisarTanques(litrosRecibidos,tanquesFull);

    }

    /**
     * Metodo encargado de verificar si el tanque esta en capacidad normal
     * superando el 70 % o en capacidad maxima excedida
     * @param litrosAdquiridos: litros a sumar
     * @param tanquesFull: en caso de que venga porque los tanques pasan su capacidad maxima
     * se envia aqui el numero de tanques de capacidad max ha sido sobrepasada
     */
    public void revisarTanques (int litrosAdquiridos, int tanquesFull){

        String respuesta= "";

        Validaciones validar = new Validaciones();
        respuesta = validar.validarCapacidad(this.capacidadMaxima, this.capacidadTanque);

        this.capacidadTanque= this.capacidadTanque + litrosAdquiridos;

        if ((this.capacidadTanque >= this.capacidadMaxima) && (!alarma)){

            ventana.DistribuidorElQuemaito();
            alarma = true;
        }

        if (respuesta.compareTo("nada") == 0){

            ventana.imprimirVista("Entrada: normal \n");
            ventana.imprimirVista("Litros Actuales: " + String.valueOf(this.capacidadTanque) + "\n\n");
        }
        else{

            if (respuesta.compareTo("70") == 0){

                if (litrosAdquiridos != 0){

                    int litrosEnviar = litrosAdquiridos*70/100;

                    this.capacidadTanque= this.capacidadTanque - litrosEnviar;

                    ventana.imprimirVista("Entrada: mayor 70 \n");
                    ventana.imprimirVista("Litros Transferidos: " + String.valueOf(litrosEnviar) + "\n");
                    ventana.imprimirVista("Litros Actuales: " + String.valueOf(this.capacidadTanque) + "\n\n");

                    this.transferirLitros(litrosEnviar,0);

                }

            }

            else{

                //Cuando el tanque tiene capacidad maxima superada
                //Cuando respuesta = max                

                if (tanquesFull == 3){

                    this.llamadaFinalizar(tanquesFull);
                }
                else{

                    if (litrosAdquiridos != 0){

                        if (!alarma){

                            ventana.DistribuidorElQuemaito();
                            alarma = true;
                        }

                        int litrosEnviar = litrosAdquiridos*70/100;

                        this.capacidadTanque= this.capacidadTanque - litrosEnviar;

                        ventana.imprimirVista("Entrada: Capacidad Maxima Sobrepasa \n");
                        ventana.imprimirVista("Litros Transferidos: " + String.valueOf(litrosEnviar) + "\n");
                        ventana.imprimirVista("Litros Actuales: " + String.valueOf(this.capacidadTanque) + "\n");
                        ventana.imprimirVista("Cantidad de Tanques Full: " + String.valueOf(tanquesFull + 1) + "\n\n");

                        this.transferirLitros(litrosEnviar, tanquesFull + 1);

                    }
                    else{

                        try{

                            if (!alarma){

                                ventana.DistribuidorElQuemaito();
                                alarma = true;
                            }
                            
                            obj = (ITanqueRemoto) Naming.lookup(url);
                            obj.revisarTanques(0,tanquesFull + 1);

                            ventana.imprimirVista("Entrada: Capacidad Maxima Sobrepasa con litros 0 \n");
                            ventana.imprimirVista("Cantidad de Tanques Full: " + String.valueOf(tanquesFull + 1) + "\n\n");

                            bitacora.escribirBitacora("Tanques: " + String.valueOf(tanquesFull) , "revisar",
                                    "Capacidad superior 70%");

                        }catch (Exception e) {

                            bitacora.escribirBitacora("Tanques: " + String.valueOf(tanquesFull), "revisar",
                                    "Error al transferir");

                        }

                    }

                }

            }

        }

    }

    /**
     * Metodo encargado de terminar cada uno de los tanques pues se cumplio la condicion
     * @param tanquesTerminados: cantidad de tanques que faltan por cerrar
     */
    public void llamadaFinalizar (int tanquesTerminados){

        if (tanquesTerminados == 1){

                try {

                    bitacora.escribirBitacoraFinal("Tanques " + numeroPropio + ": <localhost> , Capacidad: <"
                                    + this.capacidadMaxima + ">, " + "Actual: " + this.capacidadTanque);

                    this.finalize();
                    
                } catch (Throwable ex) {
                    bitacora.escribirBitacora("Tanques Full: " + String.valueOf(tanquesTerminados) , "revisar",
                                "Capacidad superior a la maxima");
                }

        }
        else{

            try{

                obj = (ITanqueRemoto) Naming.lookup(url);
                obj.llamadaFinalizar(tanquesTerminados - 1);

                        bitacora.escribirBitacora("Tanques Full: " + String.valueOf(tanquesTerminados) , "revisar",
                                "Capacidad superior a la maxima");

                this.finalize();

            }catch (Throwable ex) {

                  bitacora.escribirBitacora("Finalizar Tanques: " + String.valueOf(tanquesTerminados) , "revisar",
                          "Error al Finalizar el Tanque");

            }

        }

    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Metodos Propios">

    /**
     * Metodo que levanta el Servidor para que sea accesible a los clientes
     * @return: regresa si el levantamiento fue exitoso o no
     */
    public boolean registrarServicio(){

        try
        {
            // crea el RMIRegistry en el puerto indicado
            LocateRegistry.createRegistry(puertoPropioPrincipal);
            Naming.bind("//" + InetAddress.getLocalHost().getHostAddress() +":" + puertoPropioPrincipal + "/Tanque"+numeroPropio, this);
            System.out.println("El tanque ha sido iniciado ha sido iniciado exitosamente con el nombre \"Tanque"+numeroPropio+"\"");
            return true;
         }
         catch (Exception e)
         {
            System.out.println("Error al iniciar servidor "+"Tanque"+numeroPropio+", causa: " + e.toString());
            return false;
         }
    }

    /**
     * Busca el porcentaje de petroleo que hay en el tanque
     * @return cantidad de petroleo en el tanque en porcentaje
     *
     */
    public float getPorcentaje()
    {
        return new Validaciones().getPorcentaje(capacidadTanque, capacidadMaxima);
    }

    /**
     * Metodo de prueba de imprecion por pantalla
     * @param mensaje: lo que se desea escribir
     */
    public void metodoPrueba(String mensaje){
        ventana.imprimirVista(mensaje);
    }

    /**
     * Metodo encargado de la lectura del archivos de los litros de petroleo
     * entrantes una vez que se hayan escrito
     */
    public void leerArchivoEntradas(){

        lecturaXML lectura = new lecturaXML();
        List entradas = lectura.runLectura("litros_tanques.xml");
        XmlTanque este = null;

        if(entradas != null && entradas.size() > 0) {

            for(int i = 0 ; i < entradas.size();i++) {

                este = (XmlTanque)entradas.get(i);

            }

	}

        //Llamamos al metodo que nos permita calcular los litros del tanque
        this.revisarTanques(este.getLitrosEntrada(), 0);

    }

    // </editor-fold>

}
